﻿using Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExpressionEngine
{
    /// <summary>
    /// 表达式解析器
    /// </summary>
    public class ExpressionParser
    {
        /// <summary>
        /// 构造后缀表达式栈。
        /// 通过词法分析，获得各种类别的单词，从而依据语法规则构造后缀表达式栈
        /// </summary>
        /// <param name="expr">输入表达式</param>
        /// <returns>由各个单词构成的表达式栈</returns>
        public static Stack<string> BuildPostExpressionStack(string expr)
        {
            Stack<string> retStack = new Stack<string>();
            Stack<string> stack = new Stack<string>();
            stack.Push("ENDFLAG");
            int iPointer = 0;
            int iEndPointer = 0;
            while (iPointer < expr.Length)
            {
                // 词法分析，得到单词
                string token = getToken(expr, iPointer, ref iEndPointer);
                if (token.Equals("IF"))
                    token = "IF_ELSE";
                    
                if (token.Equals("("))
                    stack.Push(token);
                else if (TableManager.ExistOperator(token) 
                    || TableManager.ExistFunction(token)
                    || TableManager.bValueOperator(token))
                {
                    // 分析操作符
                    if (stack.Count == 1 && token.Equals("-"))
                        token = "_";
                    else if (stack.Count > 1)
                    {
                        string lastToken = stack.First();
                        if (lastToken.Equals("(") && token.Equals("-"))
                            token = "_";
                        
                        while (lastToken != "ENDFLAG"
                            && (TableManager.ExistOperator(lastToken) || TableManager.ExistFunction(lastToken) || TableManager.bValueOperator(lastToken))
                            &&TableManager.GetPriority(lastToken) >= TableManager.GetPriority(token))
                        {
                            retStack.Push(stack.Pop());
                            lastToken = stack.First();
                        }
                    }
                   
                    stack.Push(token);
                }
                else if (token.Equals(",") || token.Equals("，"))
                    while (stack.Count > 1 && !stack.First().Equals("("))
                        retStack.Push(stack.Pop());
                else if (token.Equals(")"))
                {
                    while (stack.Count > 1 && !stack.First().Equals("("))
                        retStack.Push(stack.Pop());

                    if (stack.Count > 1)
                    {
                        stack.Pop();
                        string lastToken = stack.First();
                        if (TableManager.ExistFunction(lastToken)
                            || TableManager.ExistOperator(lastToken)
                            || TableManager.bValueOperator(lastToken))
                            retStack.Push(stack.Pop());
                    }
                }
                else
                    retStack.Push(token); 

                iPointer = iEndPointer + 1;
            }

            while (!stack.First().Equals("ENDFLAG"))
                retStack.Push(stack.Pop());

            return Adjust(retStack);
        }

        #region 翻转栈内序列
        private static Stack<string> Adjust(Stack<string> retStack)
        {
            Stack<string> reverseStack = new Stack<string>();
            while (retStack.Count != 0)
                reverseStack.Push(retStack.Pop());
        
            return reverseStack;
        }
        #endregion

        /// <summary>
        /// 词法分析器
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="iPointer"></param>
        /// <param name="iEndPointer"></param>
        /// <returns></returns>
        public static string getToken(string expr, int iPointer, ref int iEndPointer)
        {
            int iPointerTemp = iPointer;
            if (iPointerTemp >= expr.Length)
                throw new Exception("词法分析中，无法找到指定的字符");

            while (iPointerTemp < expr.Length)
            {
                if (TableManager.ExistEscape(expr[iPointerTemp].ToString()))
                {
                    int iPointTempEnd = iPointerTemp;
                    string experTemp = expr[iPointerTemp].ToString();
                    while (iPointTempEnd < expr.Length - 1)
                    {
                        iPointTempEnd++;
                        if (char.IsWhiteSpace(expr[iPointTempEnd]))
                            break;

                        experTemp = experTemp + expr[iPointTempEnd];
                        if (!TableManager.ExistEscape(experTemp))
                            break;       
                    }

                    iEndPointer = iPointTempEnd == iPointerTemp ? iPointerTemp : iPointTempEnd - 1;
                    return iPointTempEnd == iPointerTemp ? expr[iPointerTemp].ToString() : expr.Substring(iPointerTemp, iPointTempEnd - iPointerTemp).Trim();
                }
                    
                if (char.IsWhiteSpace(expr[iPointerTemp]))
                {
                    iPointerTemp++;
                    continue;
                }
 
                iPointerTemp++;
                if (!(iPointerTemp < expr.Length)
                    || char.IsWhiteSpace(expr[iPointerTemp])
                    || TableManager.ExistEscape(expr[iPointerTemp].ToString()))
                    break;
            }

            if (iPointerTemp < expr.Length
                && TableManager.ExistEscape(expr[iPointerTemp].ToString()))
                iEndPointer = iPointerTemp - 1;
            else
                iEndPointer = iPointerTemp;

            return expr.Substring(iPointer, iPointerTemp - iPointer).Trim();
        }

        /// <summary>
        /// 语法分析器
        /// 根据堆栈构造表达式树(不一定是二叉树，也可能只有一个子节点，也可能有多于2个子节点)
        /// </summary>
        /// <param name="expr"></param>
        /// <returns></returns>
        public static TreeNode BuildTree(string expr)
        { 
            Stack<string> postExprStack = BuildPostExpressionStack(expr);
            Stack<string> tmpStack = DeepClone.Clone(postExprStack) as Stack<string>;
            Stack<TreeNode> nodeStack = new Stack<TreeNode>();
            while (tmpStack.Count != 0)
            {
                String token = tmpStack.Pop();
                TreeNode node = new TreeNode() { Token = token ,NodeTokenType = TableManager.GetTokenType(token)}; 
                if (node.NodeTokenType == TokenType.FUNCTION
                    || node.NodeTokenType == TokenType.OPERATOR)
                    for (int i = 0; i < TableManager.GetDimension(token); i++)
                        node.ChildNodes.Add(nodeStack.Pop());
                    
                if (node.NodeTokenType == TokenType.VARIABLE)
                    node.Token = TableManager.GetVariable(token).Name.ToString();
                    
                nodeStack.Push(node);
            }

            TreeNode root = nodeStack.Pop();
            return root; 
        }

        /// <summary>
        /// 计算表达式。 通过递归解析计算表达式树得到计算结果
        /// </summary>
        /// <param name="expr"></param>
        /// <returns></returns>
        public static Variable ComputeExpression(String expr)
        {
            Variable value = null;
            if (expr == null)
                return value;

            // 构造表达式树
            TreeNode tree = BuildTree(expr);
            if (tree == null)
                return value;

            // 解析计算表达式树
            return ComputeSubTree(tree);
        }

        /// <summary>
        /// 解析计算表达式子树
        /// </summary>
        /// <param name="tree"></param>
        /// <returns></returns>
        private static Variable ComputeSubTree(TreeNode node)
        {
            Variable varRet = null;
            if (node == null)
                return varRet;

            string value = node.Token;
            if ((!TableManager.ExistOperator(value) 
                && !TableManager.ExistFunction(value)
                && !TableManager.bValueOperator(value))
                || node.ChildNodes.Count == 0 )
                return ParserUtil.getValue(value);
            
            List<Variable> operands = new List<Variable>();
            foreach (TreeNode item in node.ChildNodes)
                operands.Add(ComputeSubTree(item));

            OperationSymbol op = GetOperationSymbol(node, value);
            if (op == null)
                return varRet;

            op.Operands = operands;
            varRet = op.operate();
            return varRet; 
        }

        #region 将数节点转换为一般操作符
        private static OperationSymbol GetOperationSymbol(TreeNode node, string value)
        {
            if (TableManager.ExistOperator(value))
                return TableManager.GetOperator(value);
            else if (TableManager.ExistFunction(value))
                return TableManager.GetFunction(value);
            else if (TableManager.bValueOperator(value))
                return ValueOperator.Instance;
            else
                throw new Exception("非法操作符");
        }
        #endregion
    }
}
